# gozerbot/threads/threadloop.py
#
#

""" class to implement start/stoppable threads. """

__status__ = "seen"

## gozerbot imports

from gozerbot.utils.log import rlog
from gozerbot.config import config
from gozerbot.utils.exception import handle_exception
from thr import start_new_thread

## basic imports

import Queue
import time

## ThreadLoop class

class ThreadLoop(object):

    """ implement startable/stoppable threads. """

    def __init__(self, name="", queue=None):
        self.name = name or 'idle'
        self.stopped = False
        self.running = False
        self.outs = []
        self.queue = queue or Queue.Queue()
        self.nowrunning = "none"

    def _loop(self):
        """ the loop that delegates to the self.handle method. """
        rlog(0, "threadloop", 'starting threadloop')
        while not self.stopped:
            try:
                self.running = True
                try: data = self.queue.get_nowait()
                except Queue.Empty:
                    if self.stopped: break
                    time.sleep(0.1)
                    continue
                if self.stopped: break
                if not data: break
                rlog(0, self.name, 'running %s' % str(data))
                self.handle(*data)
            except Exception, ex: handle_exception()
        self.running = False
        rlog(0, self.name, 'stopping threadloop')

    def put(self, *data):
        """ put data on task queue. """
        self.queue.put_nowait(data)

    def start(self):
        """ start the thread. """
        if not self.running: start_new_thread(self._loop, ())

    def stop(self):
        """ stop the thread. """
        self.stopped = True
        self.running = False
        self.queue.put(None)

    def handle(self, *args, **kwargs):
        """ overload this. """
        pass

## RunnerLoop class

class RunnerLoop(ThreadLoop):

    """ dedicated threadloop for bot commands/callbacks. """


    def _loop(self):
        """ teh loop. """
        rlog(0, "runnerloop", 'starting threadloop')
        self.running = True
        while not self.stopped:
            try: data = self.queue.get()
            except Queue.Empty:
                if self.stopped: break
                time.sleep(0.1)
                continue
            if self.stopped: break
            if not data: break
            self.nowrunning = data[0]
            rlog(0, 'runnerloop', 'now running %s' % self.nowrunning)
            self.handle(*data)
        self.running = False
        rlog(0, 'runnerloop', 'stopping threadloop')

## ThreadSleeper class

class ThreadSleeper(ThreadLoop):

    """ timed threadloop. """

    def __init__(self, name="", timeout=1800):
        ThreadLoop.__init__(self, name)
        self.timeout = timeout

    def _loop(self):
        """ looping. """
        rlog(0, 'threadsleeper', 'starting threadloop')
        self.running = True
        while not self.stopped:
            time.sleep(self.timeout)
            if self.stopped: break
            rlog(-1, self.name, 'running')
            self.handle()
        self.running = False
        rlog(0, 'threadsleeper', 'stopping threadloop')

#### BHJTW 22-01-2012
